using System;
using NUnit.Framework;
using TDUnit.Common.TestData;

namespace TDUnit.Tests
{
    [TestFixture]
    public class TestDataTests
    {
        private static readonly PrimaryKeyColumn dummyPKColumn = new PrimaryKeyColumn("PrimaryKeyColumn");

        #region Table tests

        [Test]
        public void AddTableToDatasetCreatesTable()
        {
            var ds = new TestData();
            var table = ds.AddTable("TableName", "PrimaryKeyColumnName");

            Assert.IsNotNull(table);
            Assert.AreEqual("TableName", table.Name, "Name");
            Assert.AreEqual("PrimaryKeyColumnName", table.PrimaryKeyColumnName, "PKName");
            Assert.IsFalse(table.IsPrimaryKeyAutoIdentity);
        }

        [Test]
        public void AddTableAndSetAutoIdentityToTrue()
        {
            var table = GetTable().WithAutoIdentity(true);
            Assert.IsTrue(table.IsPrimaryKeyAutoIdentity);
        }
        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void AddingTablesWithTheSameNameCausesException()
        {
            var ds = new TestData();
            ds.AddTable("TableName", "PrimaryKey");
            ds.AddTable("TableName", "PrimaryKey");
        }

        [Test]
        public void AddTableToDataSetWithAliasSetsAlias()
        {
            var ds = new TestData();
            var table = ds.AddTable("TableName", "PrimaryKeyColumnName", "TableAlias");
            Assert.AreEqual("TableAlias", table.Alias);
        }

        [Test]
        public void GetTableByNameGetsTable()
        {
            var ds = new TestData();
            var table = ds.AddTable("TableName", "PrimaryKeyColumnName");
            Assert.AreSame(table, ds.GetTable("TableName"));
        }

        [Test]
        public void GetTableByNameAlsoUsesAlias()
        {
            var ds = new TestData();
            var table = ds.AddTable("TableName", "PrimaryKeyColumnName", "TableAlias");
            Assert.AreSame(table, ds.GetTable("TableAlias"));
        }

        #endregion

        #region Row tests
        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void AddingRowToTableWithExistingRowWithSameNameThrowsException()
        {
            var table = GetTable();
            table.AddRow(dummyPKColumn, "RowName");
            table.AddRow(dummyPKColumn, "RowName");
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreatingRowWithNullTableThrowsExpcetion()
        {
            new Row(null);
        }

        [Test]
        public void AddingMultipleRowsWithNoNameToTableDoesNotThrowException()
        {
            var table = GetTable();
            table.AddRow(dummyPKColumn);
            table.AddRow(dummyPKColumn);
        }
        [Test]
        public void AddRowToTableCreatesRow()
        {
            var table = GetTable();
            Assert.AreEqual(0, table.Rows.Length, "Row Length Prior");
            table.AddRow(dummyPKColumn);
            Assert.AreEqual(1, table.Rows.Length, "Row Length Post");
        }
        [Test]
        public void NewRowContainsEmptyColumnList()
        {
            var row = CreateRow();
            Assert.AreEqual(0, row.Columns.Length);
        }

        [Test]
        public void AddNameToRowSetsName()
        {
            var row = CreateRow("RowName");
            Assert.AreEqual("RowName", row.Name);
        }

        [Test]
        public void RowGetColumnByNameReturnsNamedColumn()
        {
            var row = CreateRow();
            row.AddColumn("ColumnName");
            Assert.IsNotNull(row.GetColumn("ColumnName"));
        }

        [Test]
        public void RowGetColumnByNameReturnsNullIfNoColumnWithNameExists()
        {
            var row = CreateRow();
            row.AddColumn("ColumnName");
            Assert.IsNull(row.GetColumn("NameOfColumnNotInRow"));
        }

        #endregion

        #region Column tests
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void CreatingColumnWithNullNameThrowsException()
        {
            new Column(null);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void CreatingColumnWithEmptyNameThrowsException()
        {
            new Column(string.Empty);
        }
        [Test]
        public void CanAddColumnToRow()
        {
            var row = CreateRow();
            row.AddColumn("ColumnName");
            Assert.AreEqual(1, row.Columns.Length);
        }

        [Test]
        public void CanSetColumnValue()
        {
            var c = CreateRow().AddColumn("ColumnName").WithValue("ColumnValue");
            Assert.AreEqual("ColumnValue", c.Value);

        }

        [Test]
        public void CanSetShouldQuoteOnColumn()
        {
            var c = CreateRow().AddColumn("ColumnName").WithShouldQuote(true);
            Assert.IsTrue(c.ShouldQuote);
        }

        [Test]
        public void ShouldQuoteOnColumnUsesDefaultBehaviorAndQuotesStringWhenNotSet()
        {
            var c = CreateRow().AddColumn("ColumnName").WithValue("ColumnValue");
            Assert.IsTrue(c.ShouldQuote);
        }

        [Test]
        public void ShouldQuoteOnColumnUsesDefaultBehaviorAndDoesNotQuoteNumbersWhenNotSet()
        {
            var c = CreateRow().AddColumn("ColumnName").WithValue("1");
            Assert.IsFalse(c.ShouldQuote);
        }

        [Test]
        public void ShouldQuoteOnColumnDoesNotQuoteValueNullByDefault()
        {
            var c = CreateRow().AddColumn("ColumnName").WithValue("NULL");
            Assert.IsFalse(c.ShouldQuote);
        }

        [Test]
        public void ShouldQuoteOnColumnDoesQuoteValueNullIfSetToShouldQuote()
        {
            var c = CreateRow().AddColumn("ColumnName").WithValue("NULL").WithShouldQuote(true);
            Assert.IsTrue(c.ShouldQuote);
        }

        [Test]
        public void ColumnValueIsEmptyAndNotNullIfNotAssigned()
        {
            var col = new Column("TestColumn");
            Assert.IsNotNull(col.Value);
        }

        #endregion

        #region PrimaryKeyColumn tests
        [Test]
        public void GetColumnReturnsPrimaryKeyColumnIfNamed()
        {
            var row = CreateRow();
            row.AddColumn(dummyPKColumn.Name);
            Assert.AreSame(dummyPKColumn.Name, row.GetColumn(dummyPKColumn.Name).Name);
        }

        [Test]
        public void PrimaryKeyColumnForRowIsSet()
        {
            var row = CreateRow();
            Assert.IsNotNull(row.PrimaryKeyColumn);
        }

        [Test]
        public void IsAutoIdentityIsFalseByDefault()
        {
            var pk = new PrimaryKeyColumn("PrimaryKeyName");
            Assert.IsFalse(pk.IsAutoIdentity);
        }
        [Test]
        public void CanSetIsAutoIdentityOnPrimaryKeyColumn()
        {
            var pk = new PrimaryKeyColumn("PrimaryKeyName").WithIsAutoIdentity(true);
            Assert.IsTrue(pk.IsAutoIdentity);
        }
        #endregion

        #region DependencyColumn tests
        [Test]
        public void DependencyColumnReturnsValueOfDependedOnColumnForValue()
        {
            var dependedOn = new Column("DependedOnColumn").WithValue("DependedOnValue");
            var dependent = new DependencyColumn("DependencyColumn", dependedOn);
            Assert.AreEqual(dependedOn.Value, dependent.Value);
        }
        [Test]
        public void DependencyColumnChangesValueWithDependedOnColumnValue()
        {
            var dependedOn = new Column("DependedOnColumn").WithValue("DependedOnValue");
            var dependent = new DependencyColumn("DependencyColumn", dependedOn);
            Assert.AreEqual(dependedOn.Value, dependent.Value);
            dependedOn.Value = "New Value";
            Assert.AreEqual(dependedOn.Value, dependent.Value);
        }
        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreatingDependencyColumnWithNoDependedOnColumnThrowsException()
        {
            new DependencyColumn("DependencyColumnName", null);
        }
        [Test]
        public void DependedOnColumnIsSetOnDependencyColumn()
        {
            var dc = new DependencyColumn("DependencyColumnName", new Column("DependedOnName"));
            Assert.IsNotNull(dc.DepenedOnColumn);
        }
        #endregion

        #region Helper Methods
        private static Table GetTable()
        {
            var ds = new TestData();
            ds.AddTable("TableName", "PrimaryKeyColumnName");
            return ds.Tables[0];
        }

        private static Row CreateRow()
        {
            return CreateRow(string.Empty);
        }

        private static Row CreateRow(string name)
        {
            return GetTable().AddRow(dummyPKColumn, name);
        }
        #endregion
    }
}